package cn.com.cifi.mars.service.impl;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import cn.com.cifi.mars.util.DateUtils;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import cn.com.cifi.mars.activemq.PortalMqUtils;
import cn.com.cifi.mars.bean.bo.SysLogBO;
import cn.com.cifi.mars.bean.dto.ProjectByStagesDto;
import cn.com.cifi.mars.bean.dto.SupplyPlanNewestVersionDto;
import cn.com.cifi.mars.common.exception.MsgException;
import cn.com.cifi.mars.constant.CodeEnum;
import cn.com.cifi.mars.constant.Constants;
import cn.com.cifi.mars.constant.DimensionEnum;
import cn.com.cifi.mars.constant.FlowStatusEnum;
import cn.com.cifi.mars.constant.IsDeleteEnum;
import cn.com.cifi.mars.constant.IsSuccessEnum;
import cn.com.cifi.mars.constant.LogEventEnum;
import cn.com.cifi.mars.constant.LogSrcEnum;
import cn.com.cifi.mars.constant.LogTypeEnum;
import cn.com.cifi.mars.constant.ModuleTypeEunm;
import cn.com.cifi.mars.constant.OperatorTypeEnum;
import cn.com.cifi.mars.constant.ProcessingModeEnum;
import cn.com.cifi.mars.constant.ProcessingStateEnum;
import cn.com.cifi.mars.constant.SupplyConfirmStatusEnum;
import cn.com.cifi.mars.constant.TodoStatusEnum;
import cn.com.cifi.mars.constant.TodoTypeCodeEnum;
import cn.com.cifi.mars.entity.PortalTodo;
import cn.com.cifi.mars.entity.PortalTodoTask;
import cn.com.cifi.mars.entity.PriceVersion;
import cn.com.cifi.mars.entity.SignPlanVersion;
import cn.com.cifi.mars.entity.SupplyConfirmRecord;
import cn.com.cifi.mars.entity.SupplyConfirmRecordDetail;
import cn.com.cifi.mars.entity.SupplyPlanVersion;
import cn.com.cifi.mars.entity.SysNotice;
import cn.com.cifi.mars.entity.common.IdmUser;
import cn.com.cifi.mars.entity.common.ProjectByStages;
import cn.com.cifi.mars.mapper.mars.DmDmSupplyConfirmReportMapper;
import cn.com.cifi.mars.mapper.mars.PortalTodoMapper;
import cn.com.cifi.mars.mapper.mars.PortalTodoTaskMapper;
import cn.com.cifi.mars.mapper.mars.ProjectByStagesMapper;
import cn.com.cifi.mars.mapper.mars.SupplyConfirmRecordDetailMapper;
import cn.com.cifi.mars.mapper.mars.SupplyConfirmRecordMapper;
import cn.com.cifi.mars.mapper.mars.SupplyPlanVersionMapper;
import cn.com.cifi.mars.mapper.mars.SysNoticeMapper;
import cn.com.cifi.mars.service.CommonService;
import cn.com.cifi.mars.service.SupplyConfirmRecordDetailService;
import cn.com.cifi.mars.service.SupplyConfirmRecordService;
import cn.com.cifi.mars.service.SupplyPlanVersionService;
import cn.com.cifi.mars.service.SysLogService;
import cn.com.cifi.mars.util.LocalDateTimeUtils;
import cn.com.cifi.mars.util.UUIDUtils;
import lombok.extern.slf4j.Slf4j;

/**
 * <p>
 * 供货确认记录表 服务实现类
 * </p>
 *
 * @author yyd
 * @since 2019-11-25
 */
@Slf4j
@Service
public class SupplyConfirmRecordServiceImpl extends ServiceImpl<SupplyConfirmRecordMapper, SupplyConfirmRecord> implements SupplyConfirmRecordService {

	@Autowired
	private SupplyConfirmRecordMapper supplyConfirmRecordMapper;
	
	@Autowired
	private SupplyConfirmRecordDetailMapper supplyConfirmRecordDetailMapper;
	
	@Autowired
	private SupplyPlanVersionMapper supplyPlanVersionMapper;
	
	@Autowired
	private ProjectByStagesMapper projectByStagesMapper;
	
	@Autowired
	private CommonService commonService;
	
	@Autowired
	private SupplyPlanVersionService supplyPlanVersionService;
	
	@Autowired
	private SupplyConfirmRecordDetailService supplyConfirmRecordDetailService;
	
	@Autowired
	private PortalTodoMapper portalTodoMapper;
	
	@Autowired
	private PortalTodoTaskMapper portalTodoTaskMapper;
	
	@Autowired
	private PortalMqUtils activeMqUtils;
	
	@Autowired
	private SysLogService sysLogService;
	
	@Autowired
	private DmDmSupplyConfirmReportMapper dmDmSupplyConfirmReportMapper;
	
	@Autowired
	private SysNoticeMapper sysNoticeMapper;
	
	@Value("${PORTAL_SYSCODE}")
	private String systemCode;
	
	@Value("${wait_sys_code}")
	private String waitSyscode;

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void confirmSupply(String projectId,String versionDate,IdmUser user,String projectPrincipal) {
		String affiliationMonth = supplyPlanVersionService.getAffiliationMonth(versionDate);
		
		//当前时间不在确认供货时间内，不能确认供货
		if(!supplyPlanVersionService.isBetweenComfirmTime()) {
			throw new MsgException(CodeEnum.NOT_SUPPLY_CONFIRM);
		}
		
		//货值存在没有审批通过的战规后的版本，不能确认供货
		List<PriceVersion> priceVersionList = supplyConfirmRecordMapper.selectPriceVersion(projectId,IsDeleteEnum.NO.getKey());
		if(CollectionUtils.isNotEmpty(priceVersionList)) {
			throw new MsgException(CodeEnum.PRICE_EXIST_NOT_APPROVED);
		}
		
		//签约计划存在没有审批通过的战规后的版本，不能确认供货
		List<SignPlanVersion> signPlanVersionList = supplyConfirmRecordMapper.selectsignPlanVersion(projectId,IsDeleteEnum.NO.getKey());
		if(CollectionUtils.isNotEmpty(signPlanVersionList)) {
			throw new MsgException(CodeEnum.SIGN_EXIST_NOT_APPROVED);
		}
		
		//货值是否存在未处理的手动待办
		List<SysNotice> noticeList = sysNoticeMapper.selectNoticeByProjectId(projectId, ProcessingModeEnum.MANUAL.getKey(),ProcessingStateEnum.UNTREATED.getKey(), ModuleTypeEunm.PRICE.getKey(), IsDeleteEnum.NO.getKey());
		if(CollectionUtils.isNotEmpty(noticeList)) {
			throw new MsgException(CodeEnum.PRICE_EXIST_NOTICE);
		}
		
		String alias = user == null ? "" : user.getAlias();
		String confirmUserName = user == null ? null : user.getUsercn();
		LocalDateTime confirmTime = LocalDateTime.now();
		//保存确认记录
		SupplyConfirmRecord supplyConfirmRecord = new SupplyConfirmRecord();
		supplyConfirmRecord.setId(UUIDUtils.create());
		supplyConfirmRecord.setProjectId(projectId);
		supplyConfirmRecord.setConfirmStatus(SupplyConfirmStatusEnum.CONFIRMED.getKey());
		supplyConfirmRecord.setConfirmUserId(alias);
		supplyConfirmRecord.setConfirmTime(confirmTime);
		supplyConfirmRecord.setPrincipal(projectPrincipal);
		supplyConfirmRecord.setAffiliationMonth(affiliationMonth);
		supplyConfirmRecord.setRemark("供货确认");
		supplyConfirmRecord.setIsDelete(IsDeleteEnum.NO.getKey());
		supplyConfirmRecord.setCreateBy(alias);
		supplyConfirmRecord.setCreateTime(LocalDateTime.now());
		supplyConfirmRecord.setUpdateTime(LocalDateTime.now());
		supplyConfirmRecordMapper.insert(supplyConfirmRecord);
		
		//修改确认供货表状态
		dmDmSupplyConfirmReportMapper.updateConfirmStatus(affiliationMonth,projectId,confirmUserName,confirmTime,SupplyConfirmStatusEnum.CONFIRMED.getKey());
		
		//添加供货确认详情数据
		saveSupplyConfirmRecordDetail(projectId,affiliationMonth,user);
	}

	private void saveSupplyConfirmRecordDetail(String projectId,String affiliationMonth,IdmUser user) {
		List<SupplyConfirmRecordDetail> detailList =Collections.synchronizedList(new ArrayList<>());
		//根据项目获取各分期下最新供货计划动态版本信息
		List<SupplyPlanNewestVersionDto> list = supplyConfirmRecordDetailMapper.selectNewestVersionDetail(projectId,affiliationMonth,IsDeleteEnum.NO.getKey());
		List<String> versionIds = Collections.synchronizedList(new ArrayList<>());
		if(CollectionUtils.isNotEmpty(list)) {
			for(SupplyPlanNewestVersionDto dto : list) {
				SupplyConfirmRecordDetail detail = new SupplyConfirmRecordDetail();
				detail.setId(UUIDUtils.create());
				detail.setProjectId(projectId);
				detail.setStageId(dto.getProjectFId());
				detail.setVersionId(dto.getVersionId());
				detail.setVersionNum(dto.getVersionNum());
				detail.setAffiliationMonth(affiliationMonth);
				detail.setCreateBy(user == null ? "" : user.getAlias());
				detail.setCreateTime(LocalDateTime.now());
				detail.setUpdateTime(LocalDateTime.now());
				detail.setIsDelete(IsDeleteEnum.NO.getKey());
				detailList.add(detail);
				versionIds.add(dto.getVersionId());
			}
			supplyConfirmRecordDetailMapper.batchInsert(detailList);
			//供货计划版本添加供货确认状态
			supplyPlanVersionMapper.batchUpdateConfirmStatus(versionIds,SupplyConfirmStatusEnum.CONFIRMED.getKey());
		}
		//清除供货确认待办消息
		deleteTodoInfo(projectId,user);
		//清除项目人员收到的监控台所有（产/销/存/结）预警提醒
		deleteWarningTodo(projectId);
		
	}

	public void deleteTodoInfo(String projectId,IdmUser user) {
		List<PortalTodo> todoList =  supplyConfirmRecordMapper.selectTodoByProjectId(projectId,TodoTypeCodeEnum.SUPPLY_CONFIRM.getKey(),TodoStatusEnum.DEFAULT.getKey());
		if(CollectionUtils.isNotEmpty(todoList)) {
			for(PortalTodo todo : todoList) {
				String instanceId = todo.getInstanceId();
				//供货确认待办转已办
				transferredToOffice(instanceId,user);
			}
		}else {
			log.info(projectId+"：确认供货没有找到该项目对应的待办实例ID");
		}
	}
	
	private void deleteWarningTodo(String projectId) {
		IdmUser user=new IdmUser();;
		user.setAlias(Constants.SYS);
		user.setUsercn(Constants.SYS_NAME);
		List<String> dimension = Arrays.asList(DimensionEnum.B.getKey(),DimensionEnum.D.getKey(),DimensionEnum.E.getKey(),DimensionEnum.F.getKey());
		List<PortalTodo> todoList = supplyConfirmRecordMapper.selectWarningTodos(projectId,dimension,TodoTypeCodeEnum.EARLY_WARNING.getKey(),TodoStatusEnum.DEFAULT.getKey());
		if(CollectionUtils.isNotEmpty(todoList)) {
			for(PortalTodo todo : todoList) {
				String instanceId = todo.getInstanceId();
				commonService.cleanTodo(TodoTypeCodeEnum.EARLY_WARNING.getKey(), OperatorTypeEnum.DELETE.getKey(), "", instanceId, user);
			}
		}
	}

	/**
	 *    待办转已办
	 * @param instanceId
	 * @return
	 */
	public String transferredToOffice(String instanceId,IdmUser user) {
		log.info("##############确认待办任务-待办转已办 Start############################################");
		if(user == null) {
			user = new IdmUser();
			user.setAlias(Constants.SYS);
			user.setUsercn(Constants.SYS_NAME);
		}
		PortalTodo pt=portalTodoMapper.selectById(instanceId);
		if(null==pt){
			throw new MsgException(CodeEnum.PORTAL_TODO_IS_NULL);
		}
		pt.setOperatorType(OperatorTypeEnum.TRANSFERRED_TO_OFFICE.getKey());
		pt.setUpdateTime(LocalDateTime.now());
		//根据待办id 获取门户待办任务表
	  	List<PortalTodoTask> todoTaskList = portalTodoTaskMapper.selectByInstanceId(instanceId);
	  	for(PortalTodoTask task : todoTaskList) {
			//主要内容
	        JSONObject jsonObject = new JSONObject();
	        jsonObject.put("taskId",task.getTaskId());
	        jsonObject.put("todoType", task.getTodoType());
	        jsonObject.put("taskArriveDate", LocalDateTimeUtils.formatTime(task.getTaskArriveDate(), DateUtils.DATE_FULL_STR));
	        jsonObject.put("taskApproveId", task.getTaskApproveId());
	        jsonObject.put("taskApproveName",task.getTaskApproveName());
	        jsonObject.put("mobileTaskUrl", task.getMobileTaskUrl());
	        jsonObject.put("pcTaskUrl", task.getPcTaskUrl());
	        jsonObject.put("instanceId", task.getInstanceId());
	        jsonObject.put("systemCode", systemCode);
	        
	        //待办转已办
	        jsonObject.put("operatorType", OperatorTypeEnum.TRANSFERRED_TO_OFFICE.getKey());
	        jsonObject.put("taskDoneDate", LocalDateTimeUtils.formatTime(LocalDateTime.now(),DateUtils.DATE_FULL_STR));
	        String msg = jsonObject.toJSONString();
	        log.info("采用队列模式,msg:" + msg);
	        saveLog("待办消息","待办转已办任务",msg);
	        activeMqUtils.start(pt.getInstanceId(), msg);
		}
	  	//主任务转为已完成
		pt.setFlowStatus(FlowStatusEnum.COMPLETE.getKey());
		pt.setOperatorType(OperatorTypeEnum.UPDATE.getKey());
		//待办事项状态  [0默认 1完成 2删除]
		pt.setTodoStatus(TodoStatusEnum.COMPLETE.getKey());
		//处理人id
		pt.setHandlePersonId(user.getAlias());
		//处理人名称
		pt.setHandlePersonName(user.getUsercn());
		//处理时间
		pt.setHandleTime(LocalDateTime.now());
		pt.setUpdateTime(LocalDateTime.now());
		
		//更新主流程为已完成
		send(pt,OperatorTypeEnum.UPDATE.getKey(),"",null);
		
		int upd=portalTodoMapper.updateById(pt);
		
		log.info("##############确认待办任务-待办转已办 End############################################");
		return upd+"";
	}
	
	/**
	 * 发送消息
	 * @param pt  
	 * @param operatorType 操作类型
	 * @param taskDoneDate 待办处理时间
	 */
	public void send(PortalTodo pt,String operatorType,String taskDoneDate,List<PortalTodoTask> todoTaskList) {
		 //任务详情,注:为一个数组,其中可以包含多个任务
        List<String> taskList = new ArrayList<>();
        if(null!=todoTaskList) {
        	for (PortalTodoTask todoTask : todoTaskList) {
            	JSONObject taskItem = new JSONObject();
                taskItem.put("taskId",todoTask.getTaskId());
                taskItem.put("todoType",todoTask.getTodoType());
                taskItem.put("taskApproveId",todoTask.getTaskApproveId());
                taskItem.put("taskApproveName",todoTask.getTaskApproveName());
                taskItem.put("mobileTaskUrl",todoTask.getMobileTaskUrl());
                taskItem.put("pcTaskUrl",todoTask.getPcTaskUrl());
                taskItem.put("taskArriveDate",todoTask.getTaskArriveDate());
                taskList.add(taskItem.toJSONString());
    		}
        }
        //主要内容
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("instanceId", pt.getInstanceId());
        jsonObject.put("systemCode", systemCode);
        jsonObject.put("mobileTaskUrl", pt.getMobileTaskUrl());
        jsonObject.put("pcTaskUrl", pt.getPcTaskUrl());
        jsonObject.put("owerId", waitSyscode);
        jsonObject.put("title", pt.getTitle());
        jsonObject.put("flowStatus", pt.getFlowStatus());
        jsonObject.put("flowType", pt.getFlowType());
        jsonObject.put("flowTypeName", pt.getFlowTypeName());
        jsonObject.put("operatorType", operatorType);
        jsonObject.put("flowStartDate", pt.getFlowStartDate());
        jsonObject.put("positionCode", pt.getPositionCode());
        jsonObject.put("flowStartDate", LocalDateTimeUtils.formatTime(LocalDateTime.now(), DateUtils.DATE_FULL_STR));
        jsonObject.put("taskList", taskList);
        String msg = jsonObject.toJSONString();
        saveLog("待办消息",operatorType+"待办消息流程",msg);
        activeMqUtils.start( pt.getInstanceId(), msg);
	}
	
	private boolean saveLog(String module,String title,String content) {
		SysLogBO bo = new SysLogBO();
		bo.setEvent(LogEventEnum.TIMERTASK);
    	bo.setSource(LogSrcEnum.SYS);
    	bo.setModule(module);
    	bo.setTitle(title);
    	bo.setContent(content);
    	bo.setType(LogTypeEnum.ONE.getKey());
    	bo.setIsSuccess(IsSuccessEnum.SUCCESS.getKey());
        return sysLogService.add(bo,Constants.SYS);
	}
	
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void cancelSupplyConfirm(String projectId, String versionDate,String alias) {
		/**1、获取当前项目下，归属月份的所有动态版本
		 * 2、当前项目下所有已确认供货的版本
		 * 3、比较 供货确认后有新的版本，才可以取消供货确认
		 */
		boolean flag = false;
		String affiliationMonth = supplyPlanVersionService.getAffiliationMonth("");;
		//当前时间不在确认供货时间内，不能取消确认供货
		if(!supplyPlanVersionService.isBetweenComfirmTime()) {
			throw new MsgException(CodeEnum.NOT_CANCEL_CONFIRM);
		}
		
		List<SupplyPlanVersion> newsetList = supplyPlanVersionMapper.selectNewestDynamicVersion(projectId,affiliationMonth,IsDeleteEnum.NO.getKey());
		String versionId= "";
		for(SupplyPlanVersion version : newsetList) {
			if(version.getConfirmStatus().intValue() == 0) {
				flag = true;
				versionId = version.getId();
			}
		}
		if(!flag) {
			throw new MsgException(CodeEnum.NOT_CANCEL_SUPPLY_CONFIRM);
		}
		supplyConfirmRecordMapper.deleteSupplyConfirmRecord(projectId,alias,affiliationMonth,IsDeleteEnum.YES.getKey());
		supplyConfirmRecordMapper.deleteSupplyConfirmRecordDetail(projectId,alias,affiliationMonth,IsDeleteEnum.YES.getKey());
		//取消供货确认状态
		supplyPlanVersionMapper.deleteConfirmStatus(projectId,affiliationMonth,SupplyConfirmStatusEnum.UNCONFIRMED.getKey(),IsDeleteEnum.NO.getKey());
		//发送待办消息
		supplyPlanVersionService.sendToDoMsg(projectId, versionId,2);
		//刷新确认供货表
		supplyConfirmRecordDetailService.initSupplyConfirmReport(affiliationMonth,projectId);

	}


	@Override
	public ProjectByStages queryParentLevel(String projectId) {
		return supplyConfirmRecordMapper.selectParentLevel(projectId);
	}

	@Override
	public ProjectByStagesDto queryByOrgId(String orgId) {
		return projectByStagesMapper.selectByOrgdepid(orgId);
	}

	@Override
	public SupplyConfirmRecord queryByProjectId(String projectId,String versionDate) {
		return supplyConfirmRecordMapper.selectByProjectId(projectId, versionDate,IsDeleteEnum.NO.getKey());
	}

	@Override
	public List<SupplyConfirmRecord> selectConfirmRecordList(String affiliationMonth) {
		return supplyConfirmRecordMapper.selectConfirmRecordList(affiliationMonth,IsDeleteEnum.NO.getKey());
	}

	@Override
	public void cleanToDo(String projectId, IdmUser user) {
		deleteTodoInfo(projectId,user);
	}
}
